原文链接:http://nshipster.com/rawoptionsettype/

用法

OC中用NS_ENUM & NS_OPTIONS用来标记C中的枚举值。
在Swift中,即使因为增加了许多特性让枚举显得比较费事比如原始值和关联值等,枚举仍然以第一类语言的身份与struct or class并驾齐驱成为基石。枚举完全的契合使用于封装一套关系相近的固定值集合,开发可以有很多机会来使用它们。

当在Swift中使用Foundation类似框架的时候,所有的NS_ENUM声明自动转换成了enum,并且减少了OC中命名的重复度:

enum UITableViewCellStyle : Int {
    case Default
    case Value1
    case Value2
    case Subtitle
}

不幸的是,对于NS_OPTIONS,Swift等价转换就有点吃力了:

struct UIViewAutoresizing : RawOptionSetType {
    init(_ value: UInt)
    var value: UInt
    static var None: UIViewAutoresizing { get }
    static var FlexibleLeftMargin: UIViewAutoresizing { get }
    static var FlexibleWidth: UIViewAutoresizing { get }
    static var FlexibleRightMargin: UIViewAutoresizing { get }
    static var FlexibleTopMargin: UIViewAutoresizing { get }
    static var FlexibleHeight: UIViewAutoresizing { get }
    static var FlexibleBottomMargin: UIViewAutoresizing { get }
}

RawOptionsSetType是Swift中与NS_OPTIONS等价(至少是相近)的东东。它是一个协议遵循RawRepresentable, Equatable, BitwiseOperationsType, 和 NilLiteralConvertible等协议。一个可选类型可以用遵循BitwiseOperationsTypestruct结构数据来表示。

为什么这么操蛋呢?好吧,同样C语言中整型比特掩码技巧在Swift枚举型中不起作用。一个枚举表示一套固定的值,而同时没有内部的机制表示这种类型值联合值。一个枚举值表面上可以定义所有可能性的联合值范围,但是对于n > 3这种,这样的组合方式是不能实现的。这里有另外的方式来让Swift中等价实现OC中的NS_OPTIONS,但是RawOptionSetType是坏种最好的。

对比句法上精确的enum类声明,RawOptionsSetType确实是使用不便并且冗余,这里指需要多行的模板代码实现属性值计算:

truct Toppings : RawOptionSetType, BooleanType {
    private var value: UInt = 0

    init(_ value: UInt) {
        self.value = value
    }

    // MARK: RawOptionSetType

    static func fromMask(raw: UInt) -> Toppings {
        return self(raw)
    }

    // MARK: RawRepresentable

    static func fromRaw(raw: UInt) -> Toppings? {
        return self(raw)
    }

    func toRaw() -> UInt {
        return value
    }

    // MARK: BooleanType

    var boolValue: Bool {
        return value != 0
    }
// MARK: BitwiseOperationsType

    static var allZeros: Toppings {
        return self(0)
    }

    // MARK: NilLiteralConvertible

    static func convertFromNilLiteral() -> Toppings {
        return self(0)
    }

    // MARK: -

    static var None: Toppings           { return self(0b0000) }
    static var ExtraCheese: Toppings    { return self(0b0001) }
    static var Pepperoni: Toppings      { return self(0b0010) }
    static var GreenPepper: Toppings    { return self(0b0100) }
    static var Pineapple: Toppings      { return self(0b1000) }
}

As of Xcode 6 Beta 6, RawOptionSetType no longer conforms to BooleanType, which is required for performing bitwise checks.

庆幸的是Swift的内置二进制整型标记可以让二进制掩码显式计算。并且只要可选型枚举定义过了,使用起来还不算太费事。。。

struct Pizza {
    enum Style {
        case Neopolitan, Sicilian, NewHaven, DeepDish
    }

    struct Toppings : RawOptionSetType { ... }

    let diameter: Int
    let style: Style
    let toppings: Toppings

    init(inchesInDiameter diameter: Int, style: Style, toppings: Toppings = .None) {
        self.diameter = diameter
        self.style = style
        self.toppings = toppings
    }
}

let dinner = Pizza(inchesInDiameter: 12, style: .Neopolitan, toppings: .Pepperoni | .GreenPepper)

检验可选枚举值是否满足某个可选条件可以像C语言一样使用符号&

extension Pizza {
    var isVegetarian: Bool {
        return toppings & Toppings.Pepperoni ? false : true
    }
}

dinner.isVegetarian // false

最后

吐槽。。。略
举个NS_OPTIONS等价代码的栗子:


struct <# Options #> : RawOptionSetType, BooleanType { private var value: UInt = 0 init(_ value: UInt) { self.value = value } var boolValue: Bool { return value != 0 } static func fromMask(raw: UInt) -> <# Options #> { return self(raw) } static func fromRaw(raw: UInt) -> <# Options #>? { return self(raw) } func toRaw() -> UInt { return value } static var allZeros: <# Options #> { return self(0) } static func convertFromNilLiteral() -> <# Options #> { return self(0) } static var None: <# Options #> { return self(0b0000) } static var <# Option #>: <# Options #> { return self(0b0001) } // ... }

Cruise_Chan
729 声望71 粉丝

技能树点歪了...咋办